package com.print;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.PrintQuality;
import javax.print.attribute.standard.PrinterName;

import org.krysalis.barcode4j.HumanReadablePlacement;
import org.krysalis.barcode4j.impl.code128.Code128Bean;
import org.krysalis.barcode4j.impl.code39.Code39Bean;
import org.krysalis.barcode4j.impl.datamatrix.DataMatrixBean;
import org.krysalis.barcode4j.impl.datamatrix.SymbolShapeHint;
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;
import org.krysalis.barcode4j.tools.UnitConv;

import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.swetake.util.Qrcode;

/**
 * 标签类
 * 
 * @author C1009605
 * 
 */
public class Label {

    private static final int resolution;

    private double width = 114.3;
    private double height = 114.3;
    private int dpi = 300;

    private BufferedImage bi;
    private Graphics2D graphics;

    static {
        resolution = Toolkit.getDefaultToolkit().getScreenResolution();
    }

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public int getDpi() {
        return dpi;
    }

    public void setDpi(int dpi) {
        this.dpi = dpi;
    }

    /**
     * 初始化标签
     * 
     * @param width
     * @param height
     * @param dpi
     */
    private void init(double width, double height, int dpi) {
        int w = UnitConv.mm2px(width, dpi);
        int h = UnitConv.mm2px(height, dpi);
        bi = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);
        graphics = bi.createGraphics();
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, w, h);
        graphics.setColor(Color.BLACK);
    }

    public Label(double width, double height, int dpi) {
        this.width = width;
        this.height = height;
        this.dpi = dpi;
        init(width, height, dpi);
    }

    public Label(double width, double height) {
        this.width = width;
        this.height = height;
        init(this.width, this.height, dpi);
    }

    public Label() {
        init(width, height, dpi);
    }

    /**
     * 添加标签文本
     * 
     * @param text
     * @return
     */
    public Label addText(Text text) {
        int x = UnitConv.mm2px(text.getX(), dpi);
        int y = UnitConv.mm2px(text.getY(), dpi);
        double n = dpi / resolution;
        int fontSize = (int) Math.round(text.getFontSize() * n);
        Font font = new Font(text.getFontName(), text.getFontStyle(), fontSize);
        graphics.setFont(font);
        graphics.drawString(text.getText(), x, y);
        return this;
    }

    /**
     * 添加标签条码
     * 
     * @param code
     * @return
     * @throws IOException
     */
    public Label addCode(Code code) throws IOException {
        int x = UnitConv.mm2px(code.getX(), dpi);
        int y = UnitConv.mm2px(code.getY(), dpi);
        Code39Bean bean = new Code39Bean();
        bean.setMsgPosition(HumanReadablePlacement.HRP_NONE);
        bean.doQuietZone(false);
        bean.setHeight(code.getHeight());
        bean.setModuleWidth(code.getModuleWidth());
        BitmapCanvasProvider canvas = new BitmapCanvasProvider(dpi, BufferedImage.TYPE_BYTE_BINARY, true, 0);
        bean.generateBarcode(canvas, code.getValue());
        canvas.finish();
        BufferedImage bi = canvas.getBufferedImage();
        graphics.drawImage(bi, x, y, bi.getWidth(), bi.getHeight(), Color.WHITE, null);
        return this;
    }
    /**
     * 添加标签条码
     * 
     * @param code
     * @return
     * @throws IOException
     */
    public Label addCodes(Code code) throws IOException {
        int x = UnitConv.mm2px(code.getX(), dpi);
        int y = UnitConv.mm2px(code.getY(), dpi);
        Code128Bean bean = new Code128Bean();
       // bean.setMsgPosition(HumanReadablePlacement.HRP_NONE);

        bean.setFontName("宋体");
        bean.setFontSize(4);
        bean.doQuietZone(false);
        bean.setHeight(code.getHeight());
        bean.setModuleWidth(code.getModuleWidth());
        BitmapCanvasProvider canvas = new BitmapCanvasProvider(300, BufferedImage.TYPE_BYTE_BINARY, true, 0);
        bean.generateBarcode(canvas, code.getValue());
        canvas.finish();
        BufferedImage bi = canvas.getBufferedImage();
        graphics.drawImage(bi, x, y, bi.getWidth(), bi.getHeight(), Color.WHITE, null);
        return this;
    }
    /**
     * 添加标签条码
     * 
     * @param code128
     * @return
     * @throws IOException
     */
    public Label addCode128(Code code) throws IOException {
        int x = UnitConv.mm2px(code.getX(), dpi);
        int y = UnitConv.mm2px(code.getY(), dpi);
        Code128Bean bean = new Code128Bean();
        bean.setMsgPosition(HumanReadablePlacement.HRP_NONE);
        bean.doQuietZone(false);
        bean.setHeight(code.getHeight());
        bean.setModuleWidth(code.getModuleWidth());
        BitmapCanvasProvider canvas = new BitmapCanvasProvider(dpi, BufferedImage.TYPE_BYTE_BINARY, true, 0);
        bean.generateBarcode(canvas, code.getValue());
        canvas.finish();
        BufferedImage bi = canvas.getBufferedImage();
        graphics.drawImage(bi, x, y, bi.getWidth(), bi.getHeight(), Color.WHITE, null);
        return this;
    }

    /**
     * 添加标签条码
     * 
     * @param code
     * @return
     * @throws IOException
     */
    public Label addDMCode(DMCode code) throws IOException {
        int x = UnitConv.mm2px(code.getX(), dpi);
        int y = UnitConv.mm2px(code.getY(), dpi);
        DataMatrixBean bean = new DataMatrixBean();
        bean.setShape(SymbolShapeHint.FORCE_SQUARE);
        // bean.setModuleWidth(UnitConv.in2mm(1.0 / 72));
        BitmapCanvasProvider canvas = new BitmapCanvasProvider(dpi, BufferedImage.TYPE_BYTE_BINARY, true, 0);
        bean.generateBarcode(canvas, code.getValue());
        canvas.finish();
        BufferedImage bi = canvas.getBufferedImage();
        graphics.drawImage(bi, x, y, bi.getWidth(), bi.getHeight(), Color.WHITE, null);
        return this;
    }

    /**
     * 添加标签线段
     * 
     * @param line
     * @return
     */
    public Label addLine(Line line) {
        int x = UnitConv.mm2px(line.getX(), dpi);
        int y = UnitConv.mm2px(line.getY(), dpi);
        int length = UnitConv.mm2px(line.getLength(), dpi);
        int lineWidth = UnitConv.mm2px(line.getLineWidth(), dpi) / 2;
        double r = line.getDirection() * Math.PI / 180;
        double s = Math.sin(r);
        double c = Math.cos(r);
        int x11 = (int) (x - lineWidth * s);
        int x12 = (int) (x + lineWidth * s);
        int y11 = (int) (y - lineWidth * c);
        int y12 = (int) (y + lineWidth * c);
        x = (int) (x + length * c);
        y = (int) (y - length * s);
        int x21 = (int) (x + lineWidth * s);
        int x22 = (int) (x - lineWidth * s);
        int y21 = (int) (y + lineWidth * c);
        int y22 = (int) (y - lineWidth * c);
        int[] xPoints = new int[] { x11, x12, x21, x22 };
        int[] yPoints = new int[] { y11, y12, y21, y22 };
        graphics.fillPolygon(xPoints, yPoints, 4);
        return this;
    }

    /**
     * 添加标签圆圈
     * 
     * @param circle
     * @return
     */
    public Label addCircle(Circle circle) {
        int x = UnitConv.mm2px(circle.getX(), dpi);
        int y = UnitConv.mm2px(circle.getY(), dpi);
        int r = UnitConv.mm2px(circle.getR(), dpi);
        int lineWidth = UnitConv.mm2px(circle.getLineWidth(), dpi);
        graphics.fillOval(x - r, y - r, 2 * r, 2 * r);
        graphics.setColor(Color.WHITE);
        r -= lineWidth;
        graphics.fillOval(x - r, y - r, 2 * r, 2 * r);
        graphics.setColor(Color.BLACK);
        return this;
    }

    /**
     * 添加标签矩形框
     * 
     * @param rectangle
     * @return
     */
    public Label addRectangle(Rectangle rectangle) {
        int x = UnitConv.mm2px(rectangle.getX(), dpi);
        int y = UnitConv.mm2px(rectangle.getY(), dpi);
        int width = UnitConv.mm2px(rectangle.getWidth(), dpi);
        int height = UnitConv.mm2px(rectangle.getHeight(), dpi);
        int lineWidth = UnitConv.mm2px(rectangle.getLineWidth(), dpi);
        graphics.fillRect(x, y, width, height);
        graphics.setColor(Color.WHITE);
        x += lineWidth;
        y += lineWidth;
        width -= 2 * lineWidth;
        height -= 2 * lineWidth;
        graphics.fillRect(x, y, width, height);
        graphics.setColor(Color.BLACK);
        return this;
    }

    /**
     * 清除所有标签项
     * 
     */
    public void reset() {
        int width = UnitConv.mm2px(this.width, dpi);
        int height = UnitConv.mm2px(this.height, dpi);
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, width, height);
        graphics.setColor(Color.BLACK);
    }

    /**
     * 打印标签
     * 
     * @throws ImageFormatException
     * 
     * @throws IOException
     * @throws PrintException
     */
    public void print() throws ImageFormatException, IOException, PrintException {
        byte[] byteArray = getBytes();
        PrintService service = PrintServiceLookup.lookupDefaultPrintService();
        DocPrintJob job = service.createPrintJob();
        DocAttributeSet das = new HashDocAttributeSet();
        Doc doc = new SimpleDoc(byteArray, DocFlavor.BYTE_ARRAY.JPEG, das);
        PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
        pras.add(new MediaPrintableArea(0, 0, (float) width, (float) height, MediaPrintableArea.MM));
        pras.add(PrintQuality.HIGH);
        job.print(doc, pras);
    }

    public void print(String printerName) throws ImageFormatException, IOException, PrintException {
        HashAttributeSet has = new HashAttributeSet();
        has.add(new PrinterName(printerName, null));
        byte[] byteArray = getBytes();
        PrintService[] services = PrintServiceLookup.lookupPrintServices(null, has);
        PrintService service = null;
        if (services == null || services.length == 0) {
            service = PrintServiceLookup.lookupDefaultPrintService();
        } else {
            service = services[0];
        }
        DocPrintJob job = service.createPrintJob();
        DocAttributeSet das = new HashDocAttributeSet();
        Doc doc = new SimpleDoc(byteArray, DocFlavor.BYTE_ARRAY.JPEG, das);
        PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
        pras.add(new MediaPrintableArea(0, 0, (float) width, (float) height, MediaPrintableArea.MM));
        pras.add(PrintQuality.HIGH);
        job.print(doc, pras);
    }

    /**
     * 销毁标签
     * 
     */
    public void dispose() {
        graphics.dispose();
    }

    /**
     * 获取标签以JPEG编码后的字节码
     * 
     * @return
     * @throws IOException
     * @throws ImageFormatException
     */
    public byte[] getBytes() throws ImageFormatException, IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(baos);
        JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);
        param.setQuality(1F, false);
        encoder.encode(bi, param);
        byte[] byteArray = baos.toByteArray();
        baos.close();
        return byteArray;
    }

    /**
     * 保存以JPEG编码后的图片
     * 
     * @param out
     * @throws IOException
     * @throws ImageFormatException
     */
    public void save(OutputStream out) throws ImageFormatException, IOException {
        byte[] byteArray = getBytes();
        out.write(byteArray);
    }
    
    /**
     * 添加标签二维码
     * 
     * @param code
     * @return
     * @throws IOException
     */
    public Label addQRCode(String str, Integer x, Integer y, Integer s) throws IOException {
		Qrcode rcode = new Qrcode();
		rcode.setQrcodeVersion(3);
		byte[] content = str.getBytes("utf-8");
        boolean[][] codeOut = rcode.calQrcode(content);
        for (int i = 0; i < codeOut.length; i++) {
            for (int j = 0; j < codeOut.length; j++) {
                if (codeOut[j][i]) {
                	graphics.fillRect(j * s + x, i * s + y, s, s);
                }
            }
        }
        return this;
    }

}
